package memorphic.slide.debugger
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.utils.getQualifiedClassName;
	
	import memorphic.slide.IStateView;
	import memorphic.slide.ViewState;
	
	import mx.core.Application;
	import mx.core.Container;
	import mx.core.UIComponent;
	import mx.managers.PopUpManager;

	public class ViewHighlighter
	{
		
		private var drawingArea:UIComponent;
			
		
		private var currentViews:Array;
		private var viewRoot:DisplayObjectContainer;
		
		
		private var __overlayOptions:OverlayOptions;
		
		
		public function get overlayOptions():OverlayOptions
		{
			return __overlayOptions.clone();
		}
		public function set overlayOptions(options:OverlayOptions):void
		{
			if(!options.autoRefresh && __overlayOptions.autoRefresh){
				drawingArea.root.removeEventListener(Event.RENDER, onRenderRefresh);
			}
			__overlayOptions = options.clone();
		}
		
		private var textFields:Sprite;
		
			
		public function ViewHighlighter()
		{
			
		}
		
		private function getViewList(parent:DisplayObjectContainer):Array
		{
			var views:Array = new Array();
			
			if(overlayOptions.highlightFilterLevel == HighlightFilterLevel.NONE){
				return views;
			}
			
			getViewListRecurse(parent, views);
			return views;
		}
		
		private function getViewListRecurse(parent:DisplayObjectContainer, views:Array):Array
		{
			var child:DisplayObject;
			var numChildren:int = parent.numChildren;
			for(var i:int=0; i<numChildren;i++){
				child = parent.getChildAt(i);
				if(filterDisplayObject(child)){
					views.push(child);
				}
				if(child is DisplayObjectContainer && (child.visible || overlayOptions.highlightInvisibleObjects)){
					getViewListRecurse(child as DisplayObjectContainer, views);
				}
			}
			return views;
		}
		
		
		private function filterDisplayObject(object:DisplayObject):Boolean
		{
			
			var match:Boolean = false;
			switch(overlayOptions.highlightFilterLevel){	
			case HighlightFilterLevel.EVERYTHING:
				match = (object is UIComponent);
			case HighlightFilterLevel.CONTAINERS:
				match ||= (object is Container);
			case HighlightFilterLevel.SLIDE_VIEWS:
				match ||= (object is IStateView);
			}
			return match;
		}
		
		
		private function onRenderRefresh(e:Event):void
		{
			updateHighlights();
			if(!overlayOptions.autoRefresh){
				drawingArea.root.removeEventListener(Event.RENDER, onRenderRefresh);
			}
		}
			
		private function initDrawingArea():void
		{
			if(drawingArea)
			{
				drawingArea.removeChild(textFields);
				drawingArea.graphics.clear();
			}else{
				drawingArea = new UIComponent();
				drawingArea.mouseEnabled = false;
				drawingArea.mouseChildren = false;
				PopUpManager.addPopUp(drawingArea, Application.application as DisplayObject, false);
			}
			textFields = new Sprite();
			drawingArea.addChild(textFields);
		}
		
		
		private function updateHighlights():void
		{
			initDrawingArea();
			
			currentViews = getViewList(viewRoot);

			var colors:Array = [0xFF0000,0xFF00FF,0x00FF00,0x0000FF,0x00FFFF,0x000000,0x666666,0xFFFF00];
			var col:uint;
			var s:String = "";
			var m:int = currentViews.length;
			var bounds:Rectangle;
			var objName:String;
			var obj:UIComponent;
			var objClassName:String;
			var objQualifiedClassName:String;
			var labelText:String;
			var propsText:String = "";
			var tl:Point;
			for(var j:int=0; j<m; j++){
				col = colors[j % colors.length];
				bounds = new Rectangle(0,0,DisplayObject(currentViews[j]).width, DisplayObject(currentViews[j]).height);
				tl = DisplayObject(currentViews[j]).localToGlobal(new Point(0,0));
				tl = drawingArea.globalToLocal(tl);
				bounds.x = tl.x;
				bounds.y = tl.y
				obj = currentViews[j];
				objQualifiedClassName = getQualifiedClassName(obj);
				labelText = " ";
				if(obj.id == null){
					objName = "";
				}else{
					objName = obj.id;
					if(overlayOptions.showID){
						labelText = obj.id + " ";
					}
				}
				objClassName = objQualifiedClassName.substr(objQualifiedClassName.indexOf("::")+2)
				
			
				if(overlayOptions.showClassName){
					labelText += "("+objClassName+") ";
				}
				if(obj is IStateView){
					var viewState:ViewState = IStateView(obj).currentViewState;
					var viewStateURI:String = viewState ? viewState.uri : "";
//					if(tabNavigator.selectedChild == statesPane){
//						s += "<p><font color='#"+col.toString(16)+"'>"
//							+ objName+ " ("+objClassName+")</font><br />state = " 
//							+ viewStateURI + "</p>";
//					}
					
					
					if(overlayOptions.showStateURI ){
						if(viewStateURI){
							labelText += " - "+IStateView(obj).currentViewState.uri;
						}else{
							labelText += " - [" +obj.currentState+"]"; 
						}
					}
				}

				drawContainerBorder(bounds, labelText, col);
			}			
		}
		
		
		public function highlightViews(viewRoot:DisplayObjectContainer):void
		{
			this.viewRoot = viewRoot;
			updateHighlights();
			if(overlayOptions.autoRefresh){
				drawingArea.root.addEventListener(Event.RENDER, onRenderRefresh);
			}
		}
		
		
		private function drawContainerBorder(bounds:Rectangle, name:String, col:uint):void
		{
			drawingArea.graphics.lineStyle(1, col);
			drawingArea.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
			var txt:TextField = new TextField();
			txt.alpha = 0.6;
			txt.background = true;
			txt.backgroundColor = col;
			var tf:TextFormat = new TextFormat(null, 9, getTextColorForBG(col));
			txt.x = bounds.x;
			txt.y = bounds.y;
			txt.text = name;
			txt.setTextFormat(tf);
			txt.autoSize = TextFieldAutoSize.LEFT;
			txt.selectable = false;
			txt.mouseEnabled = false;
			
			var n:int = textFields.numChildren;
			for(var i:int=0; i<n; i++){
				if(txt.getBounds(textFields).intersects(textFields.getChildAt(i).getBounds(textFields))){
					txt.y += txt.height; 
				}
			}
			textFields.addChild(txt);
		}
		
		private function getTextColorForBG(bgCol:uint):uint
		{
			const r:Number = (bgCol >> 16) * 0.8/255;
			const g:Number = ((bgCol >> 8) & 0xFF) *1.1/255;
			const b:Number = (bgCol & 0xFF) * 0.7/255;
			var brightness:Number;
			if(r > g){
				if(g > b){
					// r>g>b
					brightness = r + g;
				}else{
					//r>b>g
					//b>r>g
					brightness = r + b;
				}
			}else{
				if(r > b){
					// g>r>b 
					brightness = r + g;
				}else {
					// g>b>r
					brightness = b + g;
				}
			}
			if(brightness > 1){
				return 0x000000;
			}else{
				return 0xFFFFFF;
			}
		}
	}
}